#!/usr/local/bin/python3
# coding=utf-8
# Author:Figo Young.on.2025/1/2

import pygame
import time
import paho.mqtt.client as mqtt
import threading
from paho.mqtt import client as mqtt_client
OVER_PRESSURE = 2
MINIMUM_SPEED = 1.5
MAXINMUM_SPEED = 1
MIDDLE_SPEED = 1
OXYGEN_ADJUSTER = 1.7

# >>>>>> Mqtt协议 传输 START >>>>>>>
# 建立MQTT连接。
class Mqtt_init():
    broker = '192.168.1.154'
    port = 1883
    topic = 'O2'

    def __init__(self,broker):
        self.topic = Mqtt_init.topic  # 消息主题
        self.msg = ''  # 消息
        self.client = mqtt_client.Client()  # 创建 Mqtt对象
        self.client.on_connect = self.onconnect # 创建连接
        self.client.connect(broker, Mqtt_init.port, 60)  # 连接到mqtt服务器
        self.rc=None

    def onconnect(self,client, userdata, flags, rc):
        if rc == 0:
            self.rc=rc
            print("Connected to MQTT Broker!")
        else:
            self.rc = rc
            print("Failed to connect, return code %d\n", rc)

# MQTT订阅主题  从服务器接收主题信息（信息来自ESP32）
class Sub(Mqtt_init):
    def __init__(self,topic,msg):
        super().__init__('PC')
        self.topic=topic
        self.msg = msg
        self.client.on_message = self.on_message
        self.client.on_connect = self.on_connect

        self.client.loop_forever()


    def on_connect(self,client, userdata,flags, rc):
        # print("Connected with result code " + str(rc))

        self.client.subscribe(self.topic)

    def on_message(self,client, userdata, message):
        print("Received message '" + str(message.payload) + "' on topic '"
              + message.topic + "' with QoS " + str(message.qos))

# MQTT发布主题  发布信息到服务器（信息发送到ESP32）
class Pub(Mqtt_init):
    def __init__(self, broker):
        super().__init__(broker)

    def pubs(self, topic, msg):
        if self.rc is not None:
            if self.rc == 0:
                result = self.client.publish(topic, msg, qos=1)
                status = result[0]
                if status == 0:
                    print(f"Send `{msg}` to ESP32, topic is `{topic}`")
                else:
                    print(f"Failed to send message to ESP32, topic is {topic}")

# 数据处理
class DataControl():
    GPIO = ('空调', '气泵', '制氧机', '排气1', '排气2', '排气3', '排气4', '排气5', '排气6', '电灯', '电源开关', '紧急开关', '启动')
    GPIO_en = ('aircon', 'pump', 'oxygen', 'exhaust1', 'exhaust2', 'exhaust3', 'exhaust4',
               'exhaust5', 'exhaust6', 'light', 'power_switch', 'EMS', 'start')
    sensor = ('舱内气压', '舱内氧浓度', '运行时间')  # 传感器
    sensor_en = ('boxair', 'boxoxygen', 'runnigtime')
    adjuster = ('调节气压', '调节氧浓度', '调节时间', '调节灯光', '调节速度', '环境气压', '环境氧浓度')  # 调节参数
    broker = 'test.mosquitto.org'  # Mqtt 服务器地址。

    def __init__(self):
        self.count_time = 0
        self.reset_time = 0
        self.real_seconds = 0
        self.gpio = {}  # 用mqtt通信向单片机发送GPIO_en字典数据
        self.sensor = {}  # 用mqtt通信从单片机接收传感器的字典数据
        self.adjuster = {}  # 调节按键的数据
        self.init_reset()  # 初始化参数。
        self.mouse_x = 0
        self.mouse_y = 0
        self.mouse_down = 0
        self.mouse_up = 0
        self.mouse_down_time = 0
        self.mouse_down_duration = 0
        self.adjust_height = 610
        self.gpio_buff = {}
        self.count10 = 0
        self.buf = 0

        # 多线程执行mqtt模块
        subthread = threading.Thread(target=self.subscriber_data)
        subthread.start()
        pubthread = threading.Thread(target=self.publish_data)
        pubthread.start()

        # 多线程执行空气调节模块
        # self.tlock = threading.Lock() # 线程锁
        # airthread = threading.Thread(target=self.air_adj_by_speed)
        # airthread.start()
        # # 多线程执行氧气调节模块
        # oxythread = threading.Thread(target=self.o2_adj_by_speed)
        # oxythread.start()

    # 初始化参数
    def init_reset(self):
        # 初始化 I/O
        self.gpio = {}
        for x in DataControl.GPIO:
            self.gpio[x] = 0
        # 初始化传感器用于模拟， 实际应用时删除。
        self.sensor = {'运行时间': 0, '舱内气压': 1.00, '舱内氧浓度': 21}

        # 初始化调节数据。
        self.adjuster = {'调节气压': 1.10, '调节氧浓度': 26, '调节灯光': 25, '调节速度': 1, '调节时间': 10, '环境气压': 1.00, '环境氧浓度': 21}
        # 初始化按钮。
        self.click_but = {'氧浓度': 0, '气压': 0, '时间': 0, '灯光': 0, '速度': 1,
                          '快速': 0, '标准': 0, '慢速': 1, '调节上': 0, '调节下': 0}

    def adjust_up(self):
        self.click_but['调节上'] = 0
        self.click_but['调节下'] = 0
        if self.click_but['氧浓度'] == 1:  # 氧浓度按键激活时。
            if self.adjuster['调节氧浓度'] < 28:  # 设置氧浓度上限为26
                self.adjuster['调节氧浓度'] += 1
        elif self.click_but['气压'] == 1:  # 气压按键激活时。
            if self.adjuster['调节气压'] < 1.6:  # 设置气压上限为1.6
                self.adjuster['调节气压'] += 0.1
        elif self.click_but['时间'] == 1:  # 时间按键激活时。
            if self.adjuster['调节时间'] < 65:
                self.adjuster['调节时间'] += 5  # 每按一次 + 5分钟
        elif self.click_but['灯光'] == 1:  # 灯光按键激活时。
            self.adjuster['调节灯光'] += 1
            self.gpio['电灯'] += 1
        self.adjuster['调节气压'] = round(self.adjuster['调节气压'], 2)  # 浮点数设置为小数点后2位。

    def adjust_down(self):
        self.click_but['调节上'] = 0
        self.click_but['调节下'] = 0
        if self.click_but['氧浓度'] == 1:  # 氧浓度按键激活时。
            if self.adjuster['调节氧浓度'] > 19:  # 设置氧浓度下限为19
                self.adjuster['调节氧浓度'] -= 1
        elif self.click_but['气压'] == 1:  # 气压按键激活时。
            if self.adjuster['调节气压'] > 0.7:  # 设置气压下限为0.7
                self.adjuster['调节气压'] -= 0.1
        elif self.click_but['时间'] == 1:  # 时间按键激活时。
            if self.adjuster['调节时间'] > 1:  # 设置时间下限
                self.adjuster['调节时间'] -= 5  # 每按一次 - 5分钟
        elif self.click_but['灯光'] == 1:  # 灯光按键激活时。
            if self.adjuster['调节灯光'] > 0:
                self.adjuster['调节灯光'] -= 1
            if self.gpio['电灯'] > 0:
                self.gpio['电灯'] -= 1
        self.adjuster['调节气压'] = round(self.adjuster['调节气压'], 2)  # 浮点数设置为小数点后2位。

    # 鼠标和按键的事件
    def click_event(self):

        # >> 鼠标连续按下事件 <<
        # 按下时间从0.6秒 开始 1.6秒加快 3 秒更快。
        if 1.6 > self.mouse_down_duration > 0.6:

            time.sleep(0.25)
            # >>>> 调节上 点击事件。
            if self.mouse_y < 375 and self.mouse_y > 325 and self.mouse_x < 290 and self.mouse_x > 205:  # 调节上 点击事件。
                self.adjust_up()

                # >>>> 调节下 点击事件。
            elif self.mouse_y < 547 and self.mouse_y > 467 and self.mouse_x < 290 and self.mouse_x > 205:  # 调节下 点击事件。
                self.adjust_down()
            return
        elif 3 > self.mouse_down_duration > 1.6:
            time.sleep(0.1)
            # >>>> 调节上 点击事件。
            if self.mouse_y < 375 and self.mouse_y > 325 and self.mouse_x < 290 and self.mouse_x > 205:  # 调节上 点击事件。
                self.adjust_up()

                # >>>> 调节下 点击事件。
            elif self.mouse_y < 547 and self.mouse_y > 467 and self.mouse_x < 290 and self.mouse_x > 205:  # 调节下 点击事件。
                self.adjust_down()
            return
        elif self.mouse_down_duration > 3:
            # >>>> 调节上 点击事件。
            if self.mouse_y < 375 and self.mouse_y > 325 and self.mouse_x < 290 and self.mouse_x > 205:  # 调节上 点击事件。
                self.adjust_up()

                # >>>> 调节下 点击事件。
            elif self.mouse_y < 547 and self.mouse_y > 467 and self.mouse_x < 290 and self.mouse_x > 205:  # 调节下 点击事件。
                self.adjust_down()
            return
        # >> 鼠标按下事件 <<
        if self.mouse_down == 1:  # 按钮 按下事件。

            if self.gpio['启动'] == 1:
                if self.mouse_y < 375 and self.mouse_y > 325 and self.mouse_x < 290 and self.mouse_x > 205:  # 调节上 点击事件。
                    self.click_but['调节上'] = 1
                    self.click_but['调节下'] = 0






                elif self.mouse_y < 547 and self.mouse_y > 467 and self.mouse_x < 290 and self.mouse_x > 205:  # 调节上 点击事件。
                    self.click_but['调节上'] = 0
                    self.click_but['调节下'] = 1

        # >> 鼠标释放事件 <<
        elif self.mouse_up == 1:  # 按钮 按下事件。

            # 电源控制部分事件
            # >>> 电源开关 点击事件。
            if self.mouse_y < 770 and self.mouse_y > 690 and self.mouse_x < 190 and self.mouse_x > 110:

                if self.gpio['电源开关'] == 1:  # 电源开关 开时运作
                    # 电源开关 关事件。
                    self.init_reset()  # 初始化 IO端口，全部清零。

                else:  # 电源开关 关时运作
                    # 电源开关 开事件。

                    self.gpio['电源开关'] = 1
                    self.gpio['电灯'] = 25

            elif self.gpio['电源开关'] == 1:
                # >>> 紧急开关 点击事件。
                if self.mouse_y < 770 and self.mouse_y > 690 and self.mouse_x < 585 and self.mouse_x > 515:  # 紧急开关 点击事件。
                    if self.gpio['紧急开关'] == 1:  # 紧急开关 开时运作
                        # 紧急开关 关事件。
                        self.gpio['紧急开关'] = 0

                    else:  # 紧急开关 关时运作
                        # 紧急开关 开事件
                        self.gpio['紧急开关'] = 1
                        self.gpio['启动'] = 0
                        self.gpio['空调'] = 0
                        self.gpio['气泵'] = 0
                        self.gpio['制氧机'] = 0
                        self.gpio['排气1'] = 0
                        self.gpio['排气2'] = 0
                        self.gpio['排气3'] = 0
                        self.gpio['排气4'] = 0
                        self.gpio['排气5'] = 0
                        self.gpio['排气6'] = 0
                # >>> 启动 点击事件
                if self.gpio['紧急开关'] == 0:  # 启动必须在紧急开关开闭时才能打关
                    if self.mouse_y < 770 and self.mouse_y > 690 and self.mouse_x < 385 and self.mouse_x > 315:  # 启动 点击事件。
                        if self.gpio['启动'] == 1:  # 启动 开时运作
                            # >>>> 启动 关事件。
                            self.gpio['启动'] = 0
                            self.gpio['空调'] = 0
                            self.gpio['气泵'] = 0
                            # self.gpio['制氧机'] = 0
                            self.gpio['排气1'] = 1
                            self.gpio['排气2'] = 1
                            self.gpio['排气3'] = 1
                            self.gpio['排气4'] = 1
                            self.gpio['排气5'] = 1
                            self.gpio['排气6'] = 1


                        else:  # 启动 关时运作
                            # >>>> 启动 开事件。
                            self.gpio['启动'] = 1
                            self.gpio['气泵'] = 1
                            self.gpio['制氧机'] = 1
                            self.gpio['排气1'] = 1
                            self.gpio['排气2'] = 1
                            self.gpio['排气3'] = 1
                            self.gpio['排气4'] = 1
                            self.gpio['排气5'] = 1
                            self.gpio['排气6'] = 1

                # >>> 调节按钮部分事件 条件 仅当电源开关是On.
                # >>>> 氧浓度 点击事件。
                if self.mouse_y < 655 and self.mouse_y > 605 and self.mouse_x < 90 and self.mouse_x > 20:  # 氧浓度 点击事件。
                    self.click_but['氧浓度'] = 1
                    self.click_but['气压'] = 0
                    self.click_but['时间'] = 0
                    self.click_but['灯光'] = 0
                    self.click_but['速度'] = 0
                    self.click_but['调节上'] = 0
                    self.click_but['调节下'] = 0
                # >>>> 气压 点击事件。
                elif self.mouse_y < 655 and self.mouse_y > 605 and self.mouse_x < 175 and self.mouse_x > 115:  # 气压 点击事件。
                    self.click_but['氧浓度'] = 0
                    self.click_but['气压'] = 1
                    self.click_but['时间'] = 0
                    self.click_but['灯光'] = 0
                    self.click_but['速度'] = 0
                    self.click_but['调节上'] = 0
                    self.click_but['调节下'] = 0
                # >>>> 时间 点击事件。
                elif self.mouse_y < 655 and self.mouse_y > 605 and self.mouse_x < 255 and self.mouse_x > 195:  # 时间 点击事件。
                    self.click_but['氧浓度'] = 0
                    self.click_but['气压'] = 0
                    self.click_but['时间'] = 1
                    self.click_but['灯光'] = 0
                    self.click_but['速度'] = 0
                    self.click_but['调节上'] = 0
                    self.click_but['调节下'] = 0
                # >>>> 灯光 点击事件。
                elif self.mouse_y < 655 and self.mouse_y > 605 and self.mouse_x < 340 and self.mouse_x > 280:  # 灯光 点击事件。
                    self.click_but['氧浓度'] = 0
                    self.click_but['气压'] = 0
                    self.click_but['时间'] = 0
                    self.click_but['灯光'] = 1
                    self.click_but['速度'] = 0
                    self.click_but['调节上'] = 0
                    self.click_but['调节下'] = 0
                # >>>> 速度 点击事件.
                elif self.mouse_y < 655 and self.mouse_y > 605 and self.mouse_x < 400 and self.mouse_x > 365:  # 灯光 点击事件。
                    self.click_but['氧浓度'] = 0
                    self.click_but['气压'] = 0
                    self.click_but['时间'] = 0
                    self.click_but['灯光'] = 0
                    self.click_but['速度'] = 1
                    self.click_but['调节上'] = 0
                    self.click_but['调节下'] = 0

                if self.click_but['速度'] == 1:
                    # >>>> 快速 点击事件。
                    if self.mouse_y < 355 and self.mouse_y > 310 and self.mouse_x < 260 and self.mouse_x > 120:  # 快速 点击事件。
                        self.click_but['快速'] = 1
                        self.click_but['标准'] = 0
                        self.click_but['慢速'] = 0
                        self.click_but['氧浓度'] = 0
                        self.click_but['气压'] = 0
                        self.click_but['时间'] = 0
                        self.click_but['灯光'] = 0
                        self.click_but['速度'] = 1
                        self.click_but['调节上'] = 0
                        self.click_but['调节下'] = 0

                    # >>>> 标准 点击事件。
                    elif self.mouse_y < 435 and self.mouse_y > 390 and self.mouse_x < 260 and self.mouse_x > 120:  # 快速 点击事件。
                        self.click_but['快速'] = 0
                        self.click_but['标准'] = 1
                        self.click_but['慢速'] = 0
                        self.click_but['氧浓度'] = 0
                        self.click_but['气压'] = 0
                        self.click_but['时间'] = 0
                        self.click_but['灯光'] = 0
                        self.click_but['速度'] = 1
                        self.click_but['调节上'] = 0
                        self.click_but['调节下'] = 0

                    # >>>> 慢速 点击事件。
                    elif self.mouse_y < 515 and self.mouse_y > 470 and self.mouse_x < 260 and self.mouse_x > 120:  # 慢速 点击事件。
                        self.click_but['快速'] = 0
                        self.click_but['标准'] = 0
                        self.click_but['慢速'] = 1
                        self.click_but['氧浓度'] = 0
                        self.click_but['气压'] = 0
                        self.click_but['时间'] = 0
                        self.click_but['灯光'] = 0
                        self.click_but['速度'] = 1
                        self.click_but['调节上'] = 0
                        self.click_but['调节下'] = 0

                # >>>> 调节上 点击事件。
                elif self.mouse_y < 375 and self.mouse_y > 325 and self.mouse_x < 290 and self.mouse_x > 205:  # 调节上 点击事件。
                    self.adjust_up()
                # >>>> 调节下 点击事件。
                elif self.mouse_y < 547 and self.mouse_y > 467 and self.mouse_x < 290 and self.mouse_x > 205:  # 调节下 点击事件。
                    self.adjust_down()

        self.mouse_down = 0
        self.mouse_up = 0

    # 设置延迟执行秒数
    def delay_control(self, second, speed=1):
        second2 = second * speed

        # 不排气的间隔
        if self.count10 < second and self.count10 >= 0:
            if self.buf == 0:
                self.buf = self.real_seconds
            else:
                if self.buf != self.real_seconds:
                    self.count10 += self.real_seconds - self.buf # 间隔秒数 每秒加1秒。
            self.buf = self.real_seconds
            # print('不排气%s秒' % self.count10)
            if speed == OVER_PRESSURE:
                self.gpio['排气1'] = 1
                self.gpio['排气2'] = 1
                # print('不排气%s秒' % self.count10)
            elif speed == MINIMUM_SPEED:
                self.gpio['排气1'] = 1
                # print('不排气%s秒' % self.count10)
            elif speed == OXYGEN_ADJUSTER:
                self.gpio['制氧机'] = 1
                # print('不制氧机%s秒' % self.count10)
            elif speed == 1:
                self.gpio['排气1'] = 1
                # print('不排气%s秒' % self.count10)
        # 排气的间隔
        elif self.count10 >= second:
            if self.buf == 0:
                self.buf = self.real_seconds
            else:
                if self.buf != self.real_seconds:
                    self.count10 += self.real_seconds - self.buf
            self.buf = self.real_seconds

            if speed == OVER_PRESSURE:
                self.gpio['排气1'] = 0
                self.gpio['排气2'] = 0
                # print('排气%s秒' % self.count10)
            elif speed == MINIMUM_SPEED:
                self.gpio['排气1'] = 0
                # print('排气%s秒' % self.count10)
            elif speed == OXYGEN_ADJUSTER:
                self.gpio['制氧机'] = 0
                # print('制氧机%s秒' % self.count10)
            elif speed == 1:
                self.gpio['排气1'] = 0
            if self.count10 > (second2*2):
                self.count10 = 0
        else:
            self.count10 = 0

    # 气压自动调节
    def air_adj_by_speed(self):

        # 条件 启动开启和紧急开关关闭时。
        if self.gpio['启动'] == 1 and self.gpio['紧急开关'] == 0:  # 条件 启动开启和紧急开关关闭时。

            if self.sensor['运行时间'] >= self.adjuster['调节时间']:  # 调节时间来控制气压
                self.gpio['排气1'] = 1
                self.gpio['排气2'] = 1
                self.gpio['排气3'] = 1
                self.gpio['排气4'] = 1
                self.gpio['排气5'] = 1
                self.gpio['排气6'] = 1
                self.gpio['气泵'] = 0
                self.gpio['启动'] = 0

            elif self.sensor['舱内气压'] >= self.adjuster['调节气压']:  # 调节气压来控制气压
                # 每隔5秒打开'排气1'和'排气2' 10秒。
                self.delay_control(5, OVER_PRESSURE)


            else:  # 达到调节的时间和气压之前，控制气压。
                # >>> 气泵快速加压动作。
                if self.click_but['快速'] == 1:  # 气泵快速加压动作。
                    self.gpio['排气1'] = 1
                    self.gpio['排气2'] = 1
                    self.gpio['排气3'] = 1
                    self.gpio['排气4'] = 1
                    self.gpio['排气5'] = 1
                    self.gpio['排气6'] = 1

                # >>> 气泵中速加压动作。
                elif self.click_but['标准'] == 1:  # 每分种开气泵50秒
                    self.gpio['排气1'] = 1
                    self.gpio['排气2'] = 1
                    # 每隔5秒打开'排气1' 5秒。
                    self.delay_control(5, MIDDLE_SPEED)

                # >>> 气泵慢速加压动作。
                elif self.click_but['慢速'] == 1:  # 每分种开气泵40秒
                    self.gpio['排气1'] = 1
                    self.gpio['排气2'] = 1
                    # 每隔5秒打开'排气1' 7.5秒。
                    self.delay_control(5, MINIMUM_SPEED)

        # >>> 紧急开关打开动作。
        if self.gpio['紧急开关'] == 1:
            # if self.sensor['舱内气压'] > self.adjuster['环境气压']:
            self.gpio['排气1'] = 0
            self.gpio['排气2'] = 0
            self.gpio['排气3'] = 0
            self.gpio['排气4'] = 0
            self.gpio['排气5'] = 0
            self.gpio['排气6'] = 0
            self.gpio['制氧机'] = 0

    # 氧气自动调节
    def o2_adj_by_speed(self):
        # 条件 启动开启和紧急开关关闭时。
        if self.gpio['启动'] == 1 and self.gpio['紧急开关'] == 0:  # 条件 启动开启和紧急开关关闭时。
            if self.adjuster['调节氧浓度'] < self.sensor['舱内氧浓度']:  # 调节氧浓度来控制制氧机开关
                # 每隔5秒打开'制氧机' 8秒。
                self.delay_control(5, OXYGEN_ADJUSTER)


            else:

                self.gpio['制氧机'] = 1
                if self.gpio['制氧机'] == 1:
                    self.sensor['舱内氧浓度'] += 0.001
                elif self.gpio['制氧机'] == 0:
                    self.sensor['舱内氧浓度'] -= 0.00002
                     

    # >>>>> 从Mqtt服务器接收数据。
    def subscriber_data(self):
        self.client = mqtt.Client()

        # MQTT 回调函数，当接收到消息时会被调用
        self.client.on_message = self.on_message  # 设置回调函数
        self.client.connect(DataControl.broker)  # 连接到MQTT代理
        self.client.subscribe("O2/senser")
        self.client.loop_forever()

    def on_message(self, client, userdata, message):
        print(f"Received message: {message.payload.decode()}")
        # print("Received message '" + str(message.payload) + "' on topic '"
        #       + message.topic + "' with QoS " + str(message.qos))

        sul = message.payload.decode()  # 转换消息编码。
        sul = sul.split(':')
        for i in range(len(DataControl.sensor_en)):
            if DataControl.sensor_en[i] == sul[0]:
                 
                self.sensor[DataControl.sensor[i]] = float(sul[1])
                 

    #  >>>>  向Mqtt服务器发送数据，也就是向ESP主板发送数据。
    def publish_data(self):
        pub = Pub(DataControl.broker)
        pub.client.loop_start()
        while True:
            for i in range(len(DataControl.GPIO)):
                 
                dic = DataControl.GPIO[i]
                edic = DataControl.GPIO_en[i]
                 
                if dic in self.gpio_buff:  # 缓冲字典非空
                    # 过滤掉与上一次重复的数据。
                    if self.gpio[dic] != self.gpio_buff[dic]:
                        dc = edic + ',' + str(self.gpio[dic])
                        # 向Mqtt服务器发GPIO端口数据
                        time.sleep(0.6)
                        pub.pubs(topic="O2/GPIO", msg=dc)
                        # publish.single(topic="O2/GPIO", payload=dc, hostname="192.168.1.154")
                else:
                    dc = edic + ',' + str(self.gpio[dic])
                    # 向Mqtt服务器发GPIO端口数据
                    time.sleep(0.6)
                    pub.pubs(topic="O2/GPIO", msg=dc)
                 
                self.gpio_buff[dic] = self.gpio[dic]
                 
        # publish.multiple(msgs, hostname="192.168.1.154")

    # 模似气流增压和减压。测试用，上机时要删除
    def air_flow(self):

        if self.sensor['舱内气压'] > self.adjuster['环境气压']:
            if self.gpio['排气1'] == 0:
                self.sensor['舱内气压'] -= 0.00007
            if self.gpio['排气2'] == 0:
                self.sensor['舱内气压'] -= 0.00007
            if self.gpio['排气3'] == 0:
                self.sensor['舱内气压'] -= 0.00007
            if self.gpio['排气4'] == 0:
                self.sensor['舱内气压'] -= 0.00007
            if self.gpio['排气5'] == 0:
                self.sensor['舱内气压'] -= 0.00007
            if self.gpio['排气6'] == 0:
                self.sensor['舱内气压'] -= 0.00007
        if self.gpio['气泵'] == 1:
            self.sensor['舱内气压'] += 0.0001

    # 模似氧流增压和减压。测试用，上机时要删除
    def o2_flow(self):
        if self.gpio['制氧机'] == 1:
            self.sensor['舱内氧浓度'] += 0.0001
        elif self.gpio['制氧机'] == 0:
            self.sensor['舱内氧浓度'] -= 0.00007

    # 循环自动调节各个参数
    def adjust_auto(self):
        '''
        1.仅当紧急开关打开 且舱内气压大于环境气压时 排气。
        2.仅当电源打开 且舱内气压大于环境气压时 排气。
        3.仅当启动打开和紧急开关关闭时 控制气泵和排气阀。

        :return:
        '''
        self.air_adj_by_speed()
        self.o2_adj_by_speed()
        self.real_time()  # 运行时间计数。
        self.air_flow()  # 模似气流增压和减压，实际应用时删除。
        self.o2_flow()  # 模似氧流增压和减压，实际应用时删除。
        # self.air_adj_by_speed()  # 气压控制。
        # self.o2_adj_by_speed()  # 氧压控制。
        # self.subscriber_data()  # 从mqtt服务上接收数据。

    # 运行时间计数。
    def real_time(self):
        if self.gpio['启动'] == 1:  # 仅当机器启动才计时
            self.count_time = time.perf_counter() - self.reset_time  # 系统的运行时间的秒,每次启动后时间清零。
            # self.count_time = time.process_time()  # 系统的运行时间的秒
            self.real_seconds = time.gmtime(self.count_time)[5]  # 系统的运行时间的秒
            self.sensor['运行时间'] = time.gmtime(self.count_time)[4]  # 系统的运行时间的分
        else:
            # self.reset_time = time.perf_counter()  # 系统的运行时间的秒     else:
            self.reset_time =  time.perf_counter()-self.count_time  # 系统的运行时间的秒

# 界面类
class Gui(DataControl):
    def __init__(self):
        self.game = pygame
        self.game.init()  # game库初始化
        self.win_width = 700
        self.screen = self.game.display.set_mode((self.win_width, 830))
        self.game.display.set_caption('O2Box')  # 窗口标题。
        super().__init__()
        running = True
        while running:
            # 按键事件
            for event in self.game.event.get():
                if event.type == self.game.QUIT:  # 按下关闭按键退出程序。
                    running = False
                elif event.type == self.game.MOUSEBUTTONDOWN:  # 按下按键事件
                    self.mouse_x, self.mouse_y = event.pos  # 鼠标的位置。
                    self.mouse_down = event.button
                    self.mouse_down_time = pygame.time.get_ticks()  # 获取按下时间
                    self.click_event()

                elif event.type == self.game.MOUSEBUTTONUP:  # 释放按键事件
                    self.mouse_x, self.mouse_y = event.pos
                    self.mouse_up = event.button

                    self.mouse_down_time = 0
                    self.click_event()
            # 鼠标连续按下的时间
            if self.mouse_down_time > 0:
                self.mouse_down_duration = (
                                                   pygame.time.get_ticks() - self.mouse_down_time) / 1000.0  # 从按下时间- 当前时间 再除于1000= 毫秒时间。
                self.click_event()

            self.screen.fill((0, 0, 0))  # 屏幕刷新为黑色
            self.adjust_auto()  # 刷新数据
            self.frist_lay()  # 第一层
            self.second_lay()  # 第二层
            self.third_lay()  # 第三层
            self.right_lay()  # 第四层右边
            self.left_lay()  # 第四层左边
            self.bottom_lay()  # 第底层
            self.game.display.update()  # 窗口刷新
        self.game.quit()  # 程度退出

    # 第一层I/O端口
    def frist_lay(self):
        sep = 65
        ftexsep = 23
        stexsep = 15
        het = 50
        self.put_draw('rect-0', 0, 0, self.win_width, 110)
        # 空调 I/O
        vl = DataControl.GPIO[0]
        val = self.gpio[vl]
        if val == 0:
            self.put_text(vl, 15, 10, 'lime', ftexsep)  # 空调 关
            self.put_text('Off', 33, het, 'lime', stexsep)
        else:
            self.put_text(vl, 15, 10, 'red', ftexsep)  # 空调 开
            self.put_text('On', 33, het, 'red', stexsep)
        # 气泵 I/O
        vl = DataControl.GPIO[1]
        val = self.gpio[vl]
        if val == 0:
            self.put_text(vl, sep * 1.2, 10, 'lime', ftexsep)
            self.put_text('Off', sep * 1.4, het, 'lime', stexsep)
        else:
            self.put_text(vl, sep * 1.2, 10, 'red', ftexsep)
            self.put_text('On', sep * 1.4, het, 'red', stexsep)
        vl = DataControl.GPIO[2]
        val = self.gpio[vl]
        # 制氧机 I/O
        if val == 0:
            self.put_text(vl, sep * 2.1, 10, 'lime', ftexsep)
            self.put_text('Off', sep * 2.5, het, 'lime', stexsep)
        else:
            self.put_text(vl, sep * 2.1, 10, 'red', ftexsep)
            self.put_text('On', sep * 2.5, het, 'red', stexsep)
        # 排气1 I/O
        vl = DataControl.GPIO[3]
        val = self.gpio[vl]
        if val == 0:
            self.put_text('排气1', sep * 3.3, 10, 'lime', ftexsep)
            self.put_text('Off', sep * 3.5, het, 'lime', stexsep)
        else:
            self.put_text('排气1', sep * 3.3, 10, 'red', ftexsep)
            self.put_text('On', sep * 3.5, het, 'red', stexsep)

        # 排气2 I/O
        vl = DataControl.GPIO[4]
        val = self.gpio[vl]
        if val == 0:
            self.put_text('排气2', sep * 4.4, 10, 'lime', ftexsep)
            self.put_text('Off', sep * 4.6, het, 'lime', stexsep)
        else:
            self.put_text('排气2', sep * 4.4, 10, 'red', ftexsep)
            self.put_text('On', sep * 4.6, het, 'red', stexsep)
        # 排气3 I/O
        vl = DataControl.GPIO[5]
        val = self.gpio[vl]
        if val == 0:
            self.put_text('排气3', sep * 5.4, 10, 'lime', ftexsep)
            self.put_text('Off', sep * 5.6, het, 'lime', stexsep)
        else:
            self.put_text('排气3', sep * 5.4, 10, 'red', ftexsep)
            self.put_text('On', sep * 5.6, het, 'red', stexsep)
        # 排气4 I/O
        vl = DataControl.GPIO[6]
        val = self.gpio[vl]
        if val == 0:
            self.put_text('排气4', sep * 6.5, 10, 'lime', ftexsep)
            self.put_text('Off', sep * 6.7, het, 'lime', stexsep)
        else:
            self.put_text('排气4', sep * 6.5, 10, 'red', ftexsep)
            self.put_text('On', sep * 6.7, het, 'red', stexsep)
        # 排气5 I/O
        vl = DataControl.GPIO[7]
        val = self.gpio[vl]
        if val == 0:
            self.put_text('排气5', sep * 7.6, 10, 'lime', ftexsep)
            self.put_text('Off', sep * 7.8, het, 'lime', stexsep)
        else:
            self.put_text('排气5', sep * 7.6, 10, 'red', ftexsep)
            self.put_text('On', sep * 7.8, het, 'red', stexsep)
        # 排气6 I/O
        vl = DataControl.GPIO[8]
        val = self.gpio[vl]
        if val == 0:
            self.put_text('排气6', sep * 8.7, 10, 'lime', ftexsep)
            self.put_text('Off', sep * 8.9, het, 'lime', stexsep)
        else:
            self.put_text('排气6', sep * 8.7, 10, 'red', ftexsep)
            self.put_text('On', sep * 8.9, het, 'red', stexsep)

        # 电灯
        vl = DataControl.GPIO[9]
        val = self.gpio[vl]
        if val == 0:
            self.put_text(vl, sep * 9.8, 10, 'lime', ftexsep)
            self.put_text('Off', sep * 10.0, het, 'lime', stexsep)
        else:
            self.put_text(vl, sep * 9.8, 10, 'red', ftexsep)
            self.put_text('On', sep * 10.0, het, 'red', stexsep)

    def second_lay(self):
        self.put_text('智能高压氧舱 ', 20, 150, 'white', 20)
        self.put_text('Newtang ', 400, 130, 'white', 40)
        self.put_draw('line', 0, 180, self.win_width, 180)

    def third_lay(self):

        self.put_text('使用时间：', 150, 230, 'white', 25)
        se = str(self.sensor['运行时间']) + ':' + str(self.real_seconds)
        # rltime = str(se) + str(ce)                                                             ''
        self.put_text(se, 280, 200, 'white', 80)  # 运行时间
        self.put_text('分钟', 450, 230, 'white', 25)

    # 实时数据栏
    def right_lay(self):
        # 氧浓度
        y = 350
        x = 440
        rec_width = 120
        self.put_text('实 时 数 据', x, y - 50, 'white', 25)
        self.put_text('氧浓度', x, y, 'white', 20)
        self.put_text(str(round(self.sensor['舱内氧浓度'], 1)) + r'%', x + 80, y + 5, 'white', 20)
        self.put_draw('rect-2', x + 70, y, rec_width, 30)
        # 空气压力
        air = round(self.sensor['舱内气压'], 4)
        self.put_text('压力', x, y + 50, 'white', 20)
        self.put_text(str(air) + 'bar', x + 80, y + 55, 'white', 20)  # 氧浓度
        self.put_draw('rect-2', x + 70, y + 50, rec_width, 30)
        # 时 间
        self.put_text('时间', x, y + 100, 'white', 20)
        self.put_text(str(self.sensor['运行时间']) + '分钟', x + 80, y + 105, 'white', 20)  # 氧浓度
        self.put_draw('rect-2', x + 70, y + 100, rec_width, 30)

    # 选项栏
    def left_lay(self):
        height = 610
        # 选项切换
        val = '0'
        adj = 0
        if self.click_but['氧浓度'] == 1:
            val = self.adjuster['调节氧浓度']
            adj = val * 2
            self.put_draw('rect-4', 15, self.adjust_height - 3, 80, 30)  # 选项文字变淡
        self.put_text('氧浓度', 20, self.adjust_height, 'white', 23)  # 选项切换文字

        if self.click_but['气压'] == 1:
            val = self.adjuster['调节气压']
            adj = (val - 0.5) * 150
            self.put_draw('rect-4', 105, self.adjust_height - 3, 80, 30)
        self.put_text('压 力', 115, self.adjust_height, 'white', 23)

        if self.click_but['时间'] == 1:
            val = self.adjuster['调节时间']
            adj = val * 3
            self.put_draw('rect-4', 185, self.adjust_height - 3, 80, 30)
        self.put_text('时 间', 195, self.adjust_height, 'white', 23)

        if self.click_but['灯光'] == 1:
            val = self.adjuster['调节灯光']
            adj = val * 3
            self.put_draw('rect-4', 270, self.adjust_height - 3, 80, 30)
        self.put_text('灯 光', 280, self.adjust_height, 'white', 23)

        if self.click_but['速度'] == 1:
            val = self.adjuster['调节速度']
            adj = val * 3
            self.put_draw('rect-4', 350, self.adjust_height - 3, 80, 30)
        self.put_text('速 度', 360, self.adjust_height, 'white', 23)
        # 空气泵的速度控制
        if self.click_but['速度'] == 1:
            if self.click_but['快速'] == 1:
                self.put_draw('rect-4', 120, 310, 140, 45)
            else:
                self.put_draw('rect-2', 120, 310, 140, 45)
            self.put_text('快 速', 160, 320, 'white', 25)

            if self.click_but['标准'] == 1:
                self.put_draw('rect-4', 120, 390, 140, 45)
            else:
                self.put_draw('rect-2', 120, 390, 140, 45)
            self.put_text('标 准', 160, 400, 'white', 25)

            if self.click_but['慢速'] == 1:
                self.put_draw('rect-4', 120, 470, 140, 45)
            else:
                self.put_draw('rect-2', 120, 470, 140, 45)
            self.put_text('慢 速', 160, 480, 'white', 25)
        # 调节和刻度尺
        else:

            # 刻度尺
            ct = 30
            ch = 45
            self.put_text(str(val), 34, 514 - adj, 'white', 15)  # 刻度标注
            self.put_draw('rect-2', 30, 330, ct, 200)
            # self.put_draw('rect-1', 30 + 3, 330 + 200 - ch, ct - 5, ch)
            #  进度尺内的刻度尺
            self.put_draw('rect-1', 30 + 3, 330 + 200 - adj, ct - 5, adj)

            # 调节按钮 倒三角形
            px1 = 230
            py1 = 350
            wd = 45
            px2 = px1 + wd
            py2 = py1 + 0
            px3 = px2 - wd / 2
            py3 = py2 + wd
            # 调节文字
            self.put_text('调节', px1 - 110, py1 + 60, 'white', 35)
            # 进度尺
            self.put_draw('line', px1, py1, px2, py2)
            self.put_draw('line', px2, py2, px3, py3)
            self.put_draw('line', px3, py3, px1, py1)
            # 调节上的圆
            if self.click_but['调节上'] == 1:
                # 点击后调节圆变色
                self.put_draw('circle', px1 + (wd / 2), py1 + (wd / 2) - 5, 40, 0)
            else:
                self.put_draw('circle', px1 + (wd / 2), py1 + (wd / 2) - 5, 40, 2)

            # 调节按钮 正三角形
            px4 = px1 + wd
            py4 = py1 + 180
            px5 = px4 - wd
            py5 = py4 - 0
            px6 = px5 + wd / 2
            py6 = py5 - wd
            # 调节下的圆
            if self.click_but['调节下'] == 1:
                self.put_draw('circle', px4 - (wd / 2), py4 - (wd / 2) + 5, 40, 3)
            else:
                self.put_draw('circle', px4 - (wd / 2), py4 - (wd / 2) + 5, 40, 2)

            self.put_draw('line', px4, py4, px5, py5)
            self.put_draw('line', px5, py5, px6, py6)
            self.put_draw('line', px6, py6, px4, py4)

    # 开关栏
    def bottom_lay(self):
        ht = 730
        rd = 100
        self.put_draw('rect-0', 0, 670, self.win_width, 200)
        # 总开关按钮
        self.put_draw('circle', 150, ht, 40, 0)
        if self.gpio['电源开关'] == 1:
            self.put_text('ON/OFF', 115, ht + 50, 'red', 23)
            self.put_draw('circle', 150, ht, 10, 1)
        else:
            self.put_text('ON/OFF', 115, ht + 50, 'lime', 23)

        # 启动按钮
        self.put_draw('circle', 350, ht, 35, 0)
        if self.gpio['启动'] == 1:
            self.put_text('启动/停止', 300, ht + 50, 'red', 23)
            self.put_draw('circle', 350, ht, 10, 1)
        else:
            self.put_text('启动/停止', 300, ht + 50, 'lime', 23)
        # 紧急开关按钮
        if self.gpio['紧急开关'] == 1:
            self.put_text('紧急开关', 505, ht + 50, 'red', 23)
        else:
            self.put_text('紧急开关', 505, ht + 50, 'lime', 23)
        self.put_draw('circle', 550, ht, 40, 1)

    def put_draw(self, con, x, y, width=0, height=0):
        pos = x, y, width, height
        if con == 'rect-0':
            entity_color = 100, 160, 170
            self.game.draw.rect(self.screen, entity_color, pos, width=0)
        elif con == 'rect-1':  # 填充白色的框。
            entity_color = 255, 255, 255
            self.game.draw.rect(self.screen, entity_color, pos, width=0)
        elif con == 'rect-2':  # 按键背景色为黑，带白色框。
            entity_color = 255, 255, 255
            self.game.draw.rect(self.screen, entity_color, pos, width=2)

        elif con == 'rect-3':
            entity_color = 255, 0, 0
            self.game.draw.rect(self.screen, entity_color, pos, width=2)
        elif con == 'rect-4':
            entity_color = 55, 55, 55  # 按键按下后，颜色变淡
            self.game.draw.rect(self.screen, entity_color, pos, width=0)
        elif con == 'line':
            entity_color = 255, 255, 255
            self.game.draw.line(self.screen, entity_color, (x, y), (width, height), width=4)
        elif con == 'circle':
            if height == 0:
                entity_color = 255, 255, 255
                self.game.draw.circle(self.screen, entity_color, (x, y), width, width=0)
            elif height == 1:
                entity_color = 255, 0, 0
                self.game.draw.circle(self.screen, entity_color, (x, y), width, width=0)
            elif height == 2:
                entity_color = 255, 255, 255
                self.game.draw.circle(self.screen, entity_color, (x, y), width, width=2)
            elif height == 3:
                entity_color = 15, 15, 15
                self.game.draw.circle(self.screen, entity_color, (x, y), width, width=0)

    def put_text(self, con, x, y, clr='white', size=60):
        # blue=0,0,210
        colr = None
        if clr == 'white':
            colr = 255, 255, 255  # 白色
        elif clr == 'red':
            colr = 255, 1, 1
        elif clr == 'lime':
            colr = 0, 255, 0
        mac_font = '/System/Library/Fonts/STHeiti Medium.ttc' # 苹果电脑的字体路径
        win_font = r"C:\Windows\Fonts\simhei.ttf" # windows电脑的字体路径
        self.fonts = self.game.font.Font(win_font, size)  # 字体设置
        self.text = self.fonts.render(con, True, colr)
        # self.screen.fill(blue) # 背景颜色
        self.screen.blit(self.text, (x, y))

if __name__ == "__main__":
    win = Gui()
